#include <config.h>
#include "nemo-index-view.h"
#include "nemo-view-factory.h"
#include "nemo-icon-view.h"
#include "nemo-list-view.h"
#include "nemo-actions.h"

#define DEBUG_FLAG NEMO_DEBUG_INDEX_VIEW
#include <libnemo-private/nemo-debug.h>
#include <libnemo-private/nemo-file-utilities.h>
#include <libnemo-private/nemo-ui-utilities.h>

#include <config.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <gio/gio.h>

#define LIST_VIEW_DEFAULT_FIXED_WIDTH 120
//#define ICON_VIEW_DEFAULT_COMPACT_HEIGHT 280

typedef enum {
    INDEX_VIEW_NONE,
    INDEX_VIEW_ICON,
    INDEX_VIEW_COMPACT,
    INDEX_VIEW_LIST,
} SubViewMode;

typedef enum {
    INDEX_VIEW_LIST_HEADER,
    INDEX_VIEW_XDG,
    INDEX_VIEW_COMPUTER,
    INDEX_VIEW_NETWORK
} IndexViewCategory;

enum
{
  PROP_0,
  PROP_CURRENT_ID
};

struct NemoIndexViewDetails {
	SubViewMode view_mode;
    gchar *current_id;
    NemoWindowSlot *slot;

    GtkWidget *index_box;
    GtkWidget *event_box;

    GtkWidget *header_box;
    GtkWidget *xdg_box;
    GtkWidget *computer_box;
    GtkWidget *network_box;

    GFile *xdg_location;
    GFile *computer_location;
    GFile *network_location;

    NemoView *list_header;
    NemoView *xdg_view;
    NemoView *computer_view;
    NemoView *network_view;

    GtkWidget *xdg_count;
    GtkWidget *computer_count;
    GtkWidget *network_count;

    gboolean done_loading;
    NemoZoomLevel zoom_level;
    GList *bindings;

    int number_of_files;
};

static const gchar *xdg_dirs[] = {"DESKTOP", "DOCUMENTS", "DOWNLOAD", "MUSIC", "PICTURES", "TEMPLATES", "VIDEOS", NULL};

G_DEFINE_TYPE (NemoIndexView, nemo_index_view, NEMO_TYPE_VIEW);
static void
nemo_index_view_get_property (GObject   *object,
                              guint     prop_id,
                              GValue    *value,
                              GParamSpec    *pspec);
static void
nemo_index_view_set_property (GObject   *object,
                              guint     prop_id,
                              const GValue  *value,
                              GParamSpec    *pspec);
static void
nemo_index_view_add_file (NemoView *view, NemoFile *file, NemoDirectory *directory, gpointer user_data);
static void
nemo_index_view_remove_file (NemoView *view, NemoFile *file, NemoDirectory *directory, gpointer user_data);
static void
nemo_index_view_end_loading (NemoView *view, gboolean all_files_seen, gpointer user_data);
static void
nemo_index_view_end_file_changes (NemoView *view, gpointer user_data);
static void
nemo_index_do_update_menus (NemoIndexView *index_view, NemoView *subview);
static GList *
nemo_index_view_get_xdg_filter (void);

static GList *
get_list_view_columns (NemoView *view)
{
    GtkTreeView *tree_view = nemo_list_view_get_tree_view (NEMO_LIST_VIEW (view));
    return gtk_tree_view_get_columns (tree_view);
}

static const gchar *
nemo_index_view_get_sub_view_id (NemoIndexView *index_view)
{
    NemoIndexViewDetails *details = index_view->details;
    if (details->view_mode == INDEX_VIEW_ICON)
    {
        return NEMO_ICON_VIEW_ID;
    }
    else if (details->view_mode == INDEX_VIEW_COMPACT)
    {
        return FM_COMPACT_VIEW_ID;
    }
    else if (details->view_mode == INDEX_VIEW_LIST)
    {
        return NEMO_LIST_VIEW_ID;
    }

    return NULL;
}

static GtkWidget *
nemo_index_view_get_parent_box (NemoIndexView *index_view, IndexViewCategory category)
{
    NemoIndexViewDetails *details = index_view->details;
    GtkWidget *parent_box = NULL;
    switch (category)
    {
        case INDEX_VIEW_LIST_HEADER:
            parent_box = details->header_box;
            break;
        case INDEX_VIEW_XDG:
            parent_box = details->xdg_box;
            break;
        case INDEX_VIEW_COMPUTER:
            parent_box = details->computer_box;
            break;
        case INDEX_VIEW_NETWORK:
            parent_box = details->network_box;
            break;
        default:
            break;
    }
    return parent_box;
}

static GtkTreeViewColumn *
list_view_get_column_by_id (GList *columns, const gchar *id)
{
    GtkTreeViewColumn *column = NULL;
    while (columns != NULL)
    {
        column = columns->data;
        const gchar *cid = g_object_get_data (G_OBJECT (column), "column-id");
        if (g_strcmp0 (cid, id) == 0)
        {
            return column;
        }
        columns = columns->next;
    }
    return NULL;
}

static void
nemo_index_view_list_header_bindings (NemoIndexView *index_view, NemoView *target_view)
{
    NemoIndexViewDetails *details = index_view->details;
    if (details->view_mode == INDEX_VIEW_LIST)
    {
        GList *source_columns = get_list_view_columns (details->list_header);
        GList *target_columns = get_list_view_columns (target_view);
        GList *target = target_columns;
        while (target_columns != NULL)
        {
            GtkTreeViewColumn *source_column, *target_column;
            target_column = target_columns->data;

            const gchar *id = g_object_get_data (G_OBJECT (target_column), "column-id");
            source_column = list_view_get_column_by_id (source_columns, id);
            gint fixed_width = LIST_VIEW_DEFAULT_FIXED_WIDTH;
            GtkSortType sort_order = gtk_tree_view_column_get_sort_order (source_column);
            gboolean visible = gtk_tree_view_column_get_visible (source_column);
            if (g_strcmp0 (id, "name") == 0)
            {
                gtk_tree_view_column_set_expand (source_column, FALSE);
                gtk_tree_view_column_set_expand (target_column, FALSE);
                fixed_width = fixed_width * 2;
            }
            if (source_column)
            {
                GBinding *binding = NULL;
                binding = g_object_bind_property (source_column, "fixed-width",
                                        target_column, "fixed-width",
                                        G_BINDING_BIDIRECTIONAL);
                details->bindings = g_list_append (details->bindings, binding);

                binding = g_object_bind_property (source_column, "sort-order",
                                        target_column, "sort-order",
                                        G_BINDING_BIDIRECTIONAL);
                details->bindings = g_list_append (details->bindings, binding);

                binding = g_object_bind_property (source_column, "visible",
                                        target_column, "visible",
                                        G_BINDING_BIDIRECTIONAL);
                details->bindings = g_list_append (details->bindings, binding);
            }

            gtk_tree_view_column_set_fixed_width (target_column, fixed_width);
            gtk_tree_view_column_set_fixed_width (source_column, fixed_width);
            gtk_tree_view_column_set_sort_order (target_column, sort_order);
            gtk_tree_view_column_set_visible (target_column, visible);

            target_columns = target_columns->next;
        }
        g_list_free (source_columns);
        g_list_free (target);
    }
}

static guint
get_subview_container_height (NemoView *subview)
{
    NemoIconContainer *icon_container;
    guint icon_container_h = 0;
    if (NEMO_IS_ICON_VIEW (subview))
    {
        icon_container = nemo_icon_view_get_icon_container (NEMO_ICON_VIEW (subview));
        gtk_layout_get_size (GTK_LAYOUT (icon_container), NULL, &icon_container_h);
    }
    return icon_container_h;
}

static void
nemo_index_view_update_subview_size (NemoView *subview)
{
    if (NEMO_IS_ICON_VIEW (subview))
    {
        NemoIconContainer *icon_container = nemo_icon_view_get_icon_container (NEMO_ICON_VIEW (subview));
        guint icon_container_h = get_subview_container_height (subview);
        /*gboolean is_compact = nemo_icon_view_is_compact (subview);
        //当紧凑视图时，设置为固定高度；
        if (is_compact)
        {
            icon_container_h = ICON_VIEW_DEFAULT_COMPACT_HEIGHT;
        } */
        gtk_widget_set_size_request (GTK_WIDGET (icon_container), -1, (int)icon_container_h);
        gtk_widget_set_size_request (GTK_WIDGET (subview), -1, (int)icon_container_h);
    }
    else if (NEMO_IS_LIST_VIEW (subview))
    {
        //reset the size of list header;
        gint view_height = 25;
        gint margin_bottom = 10;
        GtkTreeView *tree_view = nemo_list_view_get_tree_view (NEMO_LIST_VIEW (subview));
        if (gtk_tree_view_get_headers_visible (tree_view))
        {
            GList *columns = get_list_view_columns (subview);
            GtkTreeViewColumn *name_column = list_view_get_column_by_id (columns, "name");
            if (name_column)
            {
                GtkWidget *button = gtk_tree_view_column_get_button (name_column);
                gtk_widget_get_preferred_height (button, NULL, &view_height);
            }
            view_height += margin_bottom;
            gtk_widget_set_size_request (GTK_WIDGET (subview), -1, view_height);
            g_list_free (columns);
        }
    }
}

static void
subview_on_size_allocate (GtkWidget    *widget,
               GdkRectangle *allocation,
               gpointer      user_data)
{
    NemoView *subview = NEMO_VIEW (widget);
    nemo_index_view_update_subview_size (subview);
}

static void
nemo_index_view_reallocate_expanders (NemoIndexView *index_view)
{
    NemoIndexViewDetails *details = index_view->details;
    GList *children = gtk_container_get_children (GTK_CONTAINER (details->index_box));
    GtkWidget *last = NULL;
    gint spacing = gtk_box_get_spacing (GTK_BOX (details->index_box));

    while (children != NULL)
    {
        GtkWidget *child = children->data;
        if (last != NULL && GTK_IS_EXPANDER (child))
        {
            GdkRectangle last_alloc, child_alloc;
            gint padding;
            gtk_widget_get_allocation (last, &last_alloc);
            gtk_widget_get_allocation (child, &child_alloc);
            gtk_container_child_get (GTK_CONTAINER (details->index_box), child, "padding", &padding, NULL);

            if (details->view_mode == INDEX_VIEW_ICON || details->view_mode == INDEX_VIEW_COMPACT)
            {
                GtkWidget *subview = gtk_bin_get_child (GTK_BIN (child));
                gint subview_h = get_subview_container_height ((NemoView *)subview);

                child_alloc.height = child_alloc.height + subview_h;
            }
            child_alloc.y = last_alloc.y + last_alloc.height + spacing + padding * 2;
            gtk_widget_size_allocate (child, &child_alloc);
        }
        last = child;
        children = children->next;
    }
}

static void
index_box_on_size_allocate (NemoIndexView *index_view,
               GdkRectangle *allocation)
{
    //expander位置和尺寸需要更新；
    nemo_index_view_reallocate_expanders (index_view);
}

static void
nemo_index_view_unselect_subview (NemoIndexView *index_view, NemoView *subview)
{
    if (subview)
    {
        GList *selection = nemo_view_get_selection (NEMO_VIEW (subview));
        if (selection)
        {
            nemo_view_set_selection (subview, NULL);
            nemo_file_list_free (selection);
        }
    }
}

static void
nemo_index_view_on_selection_changed (NemoView *subview, gpointer user_data)
{
    NemoIndexView *index_view = NEMO_INDEX_VIEW (user_data);
    NemoIndexViewDetails *details = index_view->details;
    GList *selection = nemo_view_get_selection (NEMO_VIEW (subview));
    if (!details->done_loading || selection == NULL)
    {
        return ;
    }
    if (selection)
    {
        nemo_index_do_update_menus (index_view, subview);
    }
    nemo_file_list_free (selection);
    if (subview != details->xdg_view)
    {
        nemo_index_view_unselect_subview (index_view, details->xdg_view);
    }
    if (subview != details->computer_view)
    {
        nemo_index_view_unselect_subview (index_view, details->computer_view);
    }
    if (subview != details->network_view)
    {
        nemo_index_view_unselect_subview (index_view, details->network_view);
    }
}

static void
nemo_index_view_set_zoom_level (NemoIndexView *index_view, NemoZoomLevel zoom_level)
{
    NemoIndexViewDetails *details = index_view->details;
    NemoZoomLevel old = details->zoom_level;
    if (zoom_level >= NEMO_ZOOM_LEVEL_SMALLEST &&
		zoom_level <= NEMO_ZOOM_LEVEL_LARGEST)
    {
        details->zoom_level = zoom_level;
        nemo_view_zoom_to_level (NEMO_VIEW (details->xdg_view), zoom_level);
        nemo_view_zoom_to_level (NEMO_VIEW (details->computer_view), zoom_level);
        nemo_view_zoom_to_level (NEMO_VIEW (details->network_view), zoom_level);
        if (old != zoom_level)
        {
            g_signal_emit_by_name (NEMO_VIEW(index_view), "zoom_level_changed");
        }
    }
}

static void
nemo_index_view_on_zoom_level_changed (NemoView *subview, gpointer user_data)
{
    NemoIndexView *index_view = NEMO_INDEX_VIEW (user_data);
    NemoIndexViewDetails *details = index_view->details;
    if (!details->done_loading)
    {
        return ;
    }
    NemoZoomLevel level = nemo_view_get_zoom_level (subview);
    nemo_view_zoom_to_level (NEMO_VIEW (index_view), level);

    nemo_index_view_update_subview_size (details->xdg_view);
    nemo_index_view_update_subview_size (details->computer_view);
    nemo_index_view_update_subview_size (details->network_view);
}

static GtkActionGroup *
nemo_index_view_get_action_group (NemoIndexView *index_view, const gchar *group_name)
{
    NemoWindow *window;
    GtkUIManager *ui_manager;

    window = nemo_view_get_nemo_window (NEMO_VIEW (index_view));
    ui_manager = nemo_window_get_ui_manager (window);
    return nemo_ui_get_action_group (ui_manager, group_name);
}

static GtkAction *
nemo_index_view_update_action (GtkActionGroup *action_group,
                                const gchar *action_name,
                                gboolean visible)
{
    GtkAction *action = NULL;
    action = gtk_action_group_get_action (action_group, action_name);
    if (action)
    {
        gtk_action_set_visible (action, visible);
    }
    return action;
}

static void
nemo_index_do_update_menus (NemoIndexView *index_view, NemoView *subview)
{
    //NemoIndexViewDetails *details = index_view->details;
    GtkActionGroup *action_group;
    const gchar *action_group_name;
    //gboolean visible = FALSE;

    action_group_name = "DirViewActions";
    action_group = nemo_index_view_get_action_group (index_view, action_group_name);

    if (action_group != NULL) {

    //重命名
        nemo_index_view_update_action (action_group, NEMO_ACTION_RENAME, FALSE);
    //打开
        nemo_index_view_update_action (action_group, NEMO_ACTION_OPEN, TRUE);
    //新标签打开
        nemo_index_view_update_action (action_group, NEMO_ACTION_OPEN_IN_NEW_TAB, TRUE);
    //新窗口打开
        nemo_index_view_update_action (action_group, NEMO_ACTION_LOCATION_OPEN_ALTERNATE, TRUE);
    //打开方式
        nemo_index_view_update_action (action_group, "Open With", FALSE);
    //删除
        nemo_index_view_update_action (action_group, NEMO_ACTION_DELETE, FALSE);
    //回收站
        nemo_index_view_update_action (action_group, NEMO_ACTION_TRASH, FALSE);
    //粘贴
        nemo_index_view_update_action (action_group, NEMO_ACTION_PASTE, FALSE);
    //剪切
        nemo_index_view_update_action (action_group, NEMO_ACTION_CUT, FALSE);
    //移动到
        nemo_index_view_update_action (action_group, "MoveToMenu", FALSE);
    //复制到
        nemo_index_view_update_action (action_group, "CopyToMenu", FALSE);
    //粘贴到文件夹
        nemo_index_view_update_action (action_group, NEMO_ACTION_PASTE_FILES_INTO, FALSE);
    //就地复制
        nemo_index_view_update_action (action_group, NEMO_ACTION_DUPLICATE, FALSE);
    //创建链接
        nemo_index_view_update_action (action_group, NEMO_ACTION_CREATE_LINK, FALSE);
    //创建桌面快捷方式
        // nemo_index_view_update_action (action_group, NEMO_ACTION_CREATE_DESKTOP_LINK, TRUE);
    //创建文件夹
        nemo_index_view_update_action (action_group, NEMO_ACTION_NEW_FOLDER, FALSE);
    //创建文件
        nemo_index_view_update_action (action_group, NEMO_ACTION_NEW_DOCUMENTS, FALSE);
    //在终端打开
        nemo_index_view_update_action (action_group, NEMO_ACTION_OPEN_IN_TERMINAL, FALSE);
    //全选
        nemo_index_view_update_action (action_group, NEMO_ACTION_SELECT_ALL, FALSE);
    //反选
        nemo_index_view_update_action (action_group, NEMO_ACTION_INVERT_SELECTION, FALSE);
    //选择匹配的
        nemo_index_view_update_action (action_group, NEMO_ACTION_SELECT_PATTERN, FALSE);
    //关闭卸载
        nemo_index_view_update_action (action_group, NEMO_ACTION_UNMOUNT_VOLUME, FALSE);
    }

    action_group_name = "ShellActions";
    action_group = nemo_index_view_get_action_group (index_view, action_group_name);
    //显示隐藏文件
    if (action_group != NULL) {
        nemo_index_view_update_action (action_group, NEMO_ACTION_SHOW_HIDDEN_FILES, FALSE);
    }
    action_group_name = "IconViewActions";
    action_group = nemo_index_view_get_action_group (index_view, action_group_name);
    if (action_group)
    {
        gtk_action_group_set_visible (action_group, FALSE);
    }

    action_group_name = "DirExtensionsMenuGroup";
    action_group = nemo_index_view_get_action_group (index_view, action_group_name);
    if (action_group)
    {
        gtk_action_group_set_visible (action_group, FALSE);
    }
}

static void
nemo_index_view_do_popup_menu (NemoIndexView *index_view, GdkEventButton *event, NemoView *subview)
{
    nemo_index_do_update_menus (index_view, subview);
    nemo_view_pop_up_background_context_menu (NEMO_VIEW (index_view), event);
}

static void
nemo_index_view_on_popup_context_menu (NemoView *view, GdkEventButton *event, gpointer user_data)
{
    NemoIndexView *index_view = NEMO_INDEX_VIEW (user_data);
    //NemoIndexViewDetails *details = index_view->details;
    GList *selection = nemo_view_get_selection (NEMO_VIEW (index_view));
    //无选择项时，相当于点击空白背景；
    if (!selection)
    {
        nemo_view_set_disable_menus (view, TRUE);
        nemo_index_view_do_popup_menu (index_view, event, NULL);
    } else {
        //nemo_index_do_update_menus (index_view, view);
        nemo_view_set_disable_menus (view, FALSE);
        nemo_file_list_free (selection);
    }
}

static NemoView *
nemo_index_view_get_selection_view (NemoIndexView *index_view)
{
    NemoIndexViewDetails *details = index_view->details;
    GList *selection = NULL;
    selection = nemo_view_get_selection (NEMO_VIEW (details->xdg_view));
    if (selection)
    {
        nemo_file_list_free (selection);
        return details->xdg_view;
    }
    selection = nemo_view_get_selection (NEMO_VIEW (details->computer_view));
    if (selection)
    {
        nemo_file_list_free (selection);
        return details->computer_view;
    }
    selection = nemo_view_get_selection (NEMO_VIEW (details->network_view));
    if (selection)
    {
        nemo_file_list_free (selection);
        return details->network_view;
    }
    return NULL;
}

static void
nemo_view_on_menus_updated (NemoView *view, gpointer user_data)
{
    NemoIndexView *index_view = NEMO_INDEX_VIEW (user_data);
    //nemo_index_do_update_menus (index_view, view);
    NemoView *selection_view = nemo_index_view_get_selection_view (index_view);
    if (selection_view && view != selection_view)
    {
        nemo_view_update_menus (selection_view);
    }
    nemo_index_do_update_menus (index_view, view);
}

static gboolean
subview_on_button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
    NemoIndexView *index_view = NEMO_INDEX_VIEW (user_data);
    NemoView *selection_view = NULL;
    selection_view = nemo_index_view_get_selection_view (index_view);
    if (selection_view)
    {
        if (nemo_view_get_is_renaming (selection_view))
        {
            nemo_view_grab_focus (NEMO_VIEW (index_view));
        }
        NemoIconContainer *icon_container = nemo_icon_view_get_icon_container (NEMO_ICON_VIEW (selection_view));
        
        if (NEMO_ICON_CONTAINER (widget) != icon_container)
        {
            nemo_index_view_unselect_subview (index_view, selection_view);
        }
    }
    return FALSE;
}

static void
nemo_index_view_subview_setup (NemoIndexView *index_view, IndexViewCategory category, NemoView *view)
{
    NemoIndexViewDetails *details = index_view->details;
    GtkPolicyType hpolicy, vpolicy;
    GtkWidget *parent_box = nemo_index_view_get_parent_box (index_view, category);
    nemo_view_set_parent_view (view, NEMO_VIEW (index_view));
    vpolicy = GTK_POLICY_NEVER;
    hpolicy = GTK_POLICY_NEVER;
    if (details->view_mode == INDEX_VIEW_ICON || details->view_mode == INDEX_VIEW_COMPACT)
    {
        hpolicy = GTK_POLICY_EXTERNAL;
    }
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view), hpolicy, vpolicy);
    gtk_container_add (GTK_CONTAINER (parent_box), GTK_WIDGET (view));
    gtk_widget_set_valign (GTK_WIDGET (view), GTK_ALIGN_START);

    gtk_scrolled_window_set_propagate_natural_width (GTK_SCROLLED_WINDOW (view), TRUE);
    gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (view), TRUE);

    if (details->view_mode == INDEX_VIEW_LIST && category != INDEX_VIEW_LIST_HEADER)
    {
        nemo_index_view_list_header_bindings (index_view, view);
        GtkTreeView *tree_view = nemo_list_view_get_tree_view (NEMO_LIST_VIEW (view));
        gtk_tree_view_set_headers_visible (tree_view, FALSE);
        gtk_tree_view_set_show_expanders (tree_view, FALSE);
    }

    if (details->view_mode == INDEX_VIEW_ICON || details->view_mode == INDEX_VIEW_COMPACT)
    {
        NemoIconContainer *icon_container = nemo_icon_view_get_icon_container (NEMO_ICON_VIEW (view));
        //点击子视图内的空白处，退出选择
        g_signal_connect (icon_container,
                          "button-press-event",
                          G_CALLBACK (subview_on_button_press_callback),
                          index_view);
    }

    if (details->view_mode == INDEX_VIEW_COMPACT )
    {
        nemo_icon_container_set_label_position
                    (nemo_icon_view_get_icon_container (NEMO_ICON_VIEW (view)),
                    NEMO_ICON_LABEL_POSITION_BESIDE);
    } else if (details->view_mode == INDEX_VIEW_ICON ) {
        nemo_icon_container_set_label_position
                    (nemo_icon_view_get_icon_container (NEMO_ICON_VIEW (view)),
                    NEMO_ICON_LABEL_POSITION_UNDER);
    }

    g_signal_connect (GTK_WIDGET (view),
                      "size-allocate",
                      G_CALLBACK (subview_on_size_allocate),
                      index_view);
    if (category != INDEX_VIEW_LIST_HEADER)
    {
        g_signal_connect (view,
                          "add_file",
                          G_CALLBACK (nemo_index_view_add_file),
                          index_view);
        g_signal_connect (view,
                          "remove_file",
                          G_CALLBACK (nemo_index_view_remove_file),
                          index_view);
        g_signal_connect (view,
                          "end_file_changes",
                          G_CALLBACK (nemo_index_view_end_file_changes),
                          index_view);
        g_signal_connect (view,
                          "end_loading",
                          G_CALLBACK (nemo_index_view_end_loading),
                          index_view);
        //选择互斥
        g_signal_connect (view,
                          "selection-changed",
                          G_CALLBACK (nemo_index_view_on_selection_changed),
                          index_view);
        //zoom同步
        g_signal_connect (view,
                          "zoom-level-changed",
                          G_CALLBACK (nemo_index_view_on_zoom_level_changed),
                          index_view);
        g_signal_connect (view,
                          "pre-popup-context-menu",
                          G_CALLBACK (nemo_index_view_on_popup_context_menu),
                          index_view);
        g_signal_connect (view,
                        "menus-updated",
                        G_CALLBACK (nemo_view_on_menus_updated),
                        index_view);
    }
}

static GList *
nemo_index_view_get_xdg_filter (void)
{
    GList *filter = NULL;
    guint i;
    for (i = 0; xdg_dirs[i] != NULL; i++)
    {
        const gchar *dir = xdg_dirs[i];
        gchar *path = nemo_get_xdg_dir (dir);
        GFile *file = g_file_new_for_path (path);
        gchar *uri = g_file_get_uri (file);
        gchar *pattern = g_strdup_printf ("(%s)$", uri);
        g_object_unref (file);
        g_free (path);
        g_free (uri);
        filter = g_list_append (filter, pattern);
        // filter = g_list_append (filter, uri);
    }
    return filter;
}

static gboolean
nemo_index_view_check_file_validity (NemoFile *file, NemoDirectory *directory)
{
    if (directory)
    {
        GFile *location = nemo_directory_get_location (directory);
        if (nemo_is_computer_directory (location) || nemo_is_network_directory (location))
        {
            return TRUE;
        }
    }

    gchar *file_path = nemo_file_get_path (file);
    guint i;
    gboolean validity = FALSE;
    for (i = 0; xdg_dirs[i] != NULL; i++)
    {
        const gchar *dir = xdg_dirs[i];
        gchar *path = nemo_get_xdg_dir (dir);
        if (g_strcmp0 (path, file_path) == 0)
        {
	    validity = TRUE;
            g_free (path);
            break ;
        }
        g_free (path);
    }
    g_free (file_path);
    return validity;
}

static void
nemo_index_view_sort_subview (NemoView *subview, gint sort_column_id, GtkSortType order)
{
    GtkTreeView *tree_view = nemo_list_view_get_tree_view (NEMO_LIST_VIEW (subview));
    GtkTreeModel *tree_model = gtk_tree_view_get_model (tree_view);
    gtk_tree_sortable_set_sort_column_id ((GtkTreeSortable *)tree_model, sort_column_id, order);
}

static void
sort_column_changed_callback (GtkTreeSortable *sortable, gpointer user_data)
{
    NemoIndexView *index_view = NEMO_INDEX_VIEW (user_data);
    NemoIndexViewDetails *details = index_view->details;
    gint sort_column_id;
    GtkSortType order;
    gtk_tree_sortable_get_sort_column_id (sortable, &sort_column_id, &order);
    nemo_index_view_sort_subview (details->xdg_view, sort_column_id, order);
    nemo_index_view_sort_subview (details->computer_view, sort_column_id, order);
    nemo_index_view_sort_subview (details->network_view, sort_column_id, order);
}

static void
subview_sort_columns (NemoView *subview, GtkTreeViewColumn *column, GtkTreeViewColumn *prev_view_column)
{
    GtkTreeView *tree_view;
    GList *view_columns;
    const gchar *id = NULL;
    const gchar *prev_id = NULL;
    GtkTreeViewColumn *move_column = NULL;
    GtkTreeViewColumn *prev_column = NULL;

    tree_view = nemo_list_view_get_tree_view (NEMO_LIST_VIEW (subview));
    view_columns = get_list_view_columns (subview);

    id = g_object_get_data (G_OBJECT (column), "column-id");
    move_column = list_view_get_column_by_id (view_columns, id);

    if (prev_view_column)
    {
        prev_id = g_object_get_data (G_OBJECT (prev_view_column), "column-id");
        prev_column = list_view_get_column_by_id (view_columns, prev_id);
    }
    gtk_tree_view_move_column_after (tree_view, move_column, prev_column);
    g_list_free (view_columns);
}

static void
tree_view_on_columns_changed (GtkTreeView *tree_view, gpointer user_data)
{
    NemoIndexView *index_view = NEMO_INDEX_VIEW (user_data);
    NemoIndexViewDetails *details = index_view->details;

    GList *view_columns = gtk_tree_view_get_columns (tree_view);
    GtkTreeViewColumn *prev_view_column = NULL;
    GList *l;
    for (l = view_columns; l != NULL; l = l->next) {
        subview_sort_columns (details->xdg_view, l->data, prev_view_column);
        subview_sort_columns (details->computer_view, l->data, prev_view_column);
        subview_sort_columns (details->network_view, l->data, prev_view_column);
		prev_view_column = l->data;
	}
    g_list_free (view_columns);
}

//list header is a empty view;
static void
nemo_index_view_create_list_header (NemoIndexView *index_view)
{
    NemoIndexViewDetails *details = index_view->details;
    NemoView *view = NULL;

    view = nemo_view_factory_create (NEMO_LIST_VIEW_ID, details->slot);
    details->list_header = view;
    nemo_index_view_subview_setup (index_view, INDEX_VIEW_LIST_HEADER, view);

    GtkTreeView *tree_view = nemo_list_view_get_tree_view (NEMO_LIST_VIEW (view));
    GtkTreeModel *tree_model = gtk_tree_view_get_model (tree_view);
    g_signal_connect (tree_model,
                        "sort_column_changed",
                        G_CALLBACK (sort_column_changed_callback),
                        index_view);
    //列序变化;
    g_signal_connect (tree_view,
                      "columns-changed",
                      G_CALLBACK (tree_view_on_columns_changed),
                      index_view);
}

static void
nemo_index_view_create_xdg_view (NemoIndexView *index_view)
{
    NemoIndexViewDetails *details = index_view->details;
    NemoView *view = NULL;
    GList *filter = NULL;
    const gchar *view_id = NULL;

    filter = nemo_index_view_get_xdg_filter ();

    view_id = nemo_index_view_get_sub_view_id (index_view);
    view = nemo_view_factory_create (view_id, details->slot);
    nemo_view_set_file_filter (view, filter);
    details->xdg_view = view;
    nemo_index_view_subview_setup (index_view, INDEX_VIEW_XDG, view);
    //nemo_view_load_location (view, details->xdg_location);
    g_list_free_full (filter, g_free);
}

static void
nemo_index_view_create_computer_view (NemoIndexView *index_view)
{
    NemoIndexViewDetails *details = index_view->details;
    NemoView *view = NULL;
    const gchar *view_id = NULL;
    GList *filter = NULL;

    filter = g_list_append (filter, "^[\\s\\S]+(\\.link|\\.drive|\\.mount)$");
    //filter = g_list_append (filter, "^[\\s\\S]+(\\.link)$|/media");

    view_id = nemo_index_view_get_sub_view_id (index_view);
    view = nemo_view_factory_create (view_id, details->slot);
    nemo_view_set_file_filter (view, filter);
    details->computer_view = view;
    nemo_index_view_subview_setup (index_view, INDEX_VIEW_COMPUTER, view);
    //nemo_view_load_location (view, details->computer_location);
    g_list_free (filter);
}

static void
nemo_index_view_create_network_view (NemoIndexView *index_view)
{
    NemoIndexViewDetails *details = index_view->details;
    NemoView *view = NULL;
    const gchar *view_id = NULL;
    GList *filter = NULL;

    filter = g_list_append (filter, "^[\\s\\S]+(\\.mount)$");
    //filter = g_list_append (filter, "/run/user");

    view_id = nemo_index_view_get_sub_view_id (index_view);
    view = nemo_view_factory_create (view_id, details->slot);
    nemo_view_set_file_filter (view, filter);
    details->network_view = view;
    nemo_index_view_subview_setup (index_view, INDEX_VIEW_NETWORK, view);
    //nemo_view_load_location (view, details->network_location);
    g_list_free (filter);
}

static void
nemo_index_view_update_expander_count_label (GtkWidget *label, guint count)
{
    gchar *text = g_strdup_printf ("(%d)", count);
    gtk_label_set_label (GTK_LABEL (label), text);
    g_free (text);
}

static void
nemo_index_view_add_file (NemoView *view, NemoFile *file, NemoDirectory *directory, gpointer user_data)
{
    g_return_if_fail (NEMO_IS_INDEX_VIEW (user_data));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (user_data);
    NemoIndexViewDetails *details = index_view->details;
    if (nemo_index_view_check_file_validity (file, directory) &&
		    nemo_view_should_show_file (view, file))
    {
        details->number_of_files++;

        NemoViewClass *view_class = NULL;
        guint files_count = 0;

        if (view == details->xdg_view)
        {
            view_class = NEMO_VIEW_GET_CLASS (details->xdg_view);
            files_count = 1 + view_class->get_item_count (details->xdg_view);
            nemo_index_view_update_expander_count_label (details->xdg_count, files_count);
        }
        if (view == details->computer_view)
        {
            view_class = NEMO_VIEW_GET_CLASS (details->computer_view);
            files_count = 1 + view_class->get_item_count (details->computer_view);
            nemo_index_view_update_expander_count_label (details->computer_count, files_count);
        }
        if (view == details->network_view)
        {
            view_class = NEMO_VIEW_GET_CLASS (details->network_view);
            files_count = 1 + view_class->get_item_count (details->network_view);
            nemo_index_view_update_expander_count_label (details->network_count, files_count);
            gtk_expander_set_expanded (GTK_EXPANDER (details->network_box), TRUE);
        }
        if (details->view_mode == INDEX_VIEW_LIST)
        {
            GtkTreeView *tree_view = nemo_list_view_get_tree_view (NEMO_LIST_VIEW (view));
            gtk_tree_view_columns_autosize (tree_view);
        }
    }
}

static void
nemo_index_view_begin_loading (NemoView *view)
{
    g_return_if_fail (NEMO_IS_INDEX_VIEW (view));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;

    details->number_of_files = 0;
    if (details->xdg_view)
    {
        nemo_view_load_location (details->xdg_view, details->xdg_location);
    }
    if (details->computer_view)
    {
        nemo_view_load_location (details->computer_view, details->computer_location);
    }
    if (details->network_view)
    {
        nemo_view_load_location (details->network_view, details->network_location);
    }
}

static void
nemo_index_view_clear (NemoView *view)
{
    g_return_if_fail (NEMO_IS_INDEX_VIEW (view));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;
    NemoViewClass *view_class = NULL;

    view_class = NEMO_VIEW_GET_CLASS (details->xdg_view);
    view_class->clear (details->xdg_view);

    view_class = NEMO_VIEW_GET_CLASS (details->computer_view);
    view_class->clear (details->computer_view);

    view_class = NEMO_VIEW_GET_CLASS (details->network_view);
    view_class->clear (details->network_view);

}

static void
nemo_index_view_file_changed (NemoView *view, NemoFile *file, NemoDirectory *directory)
{
    //g_print ("%s: %d: %s\n", __func__, __LINE__, nemo_file_get_uri (file));    
}

static GList *
nemo_index_view_get_selection (NemoView *view)
{
    g_return_val_if_fail (NEMO_IS_INDEX_VIEW (view), NULL);
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;
    GList *selection = NULL;

    selection = nemo_view_get_selection (NEMO_VIEW (details->xdg_view));
    if (selection == NULL)
    {
        selection = nemo_view_get_selection (NEMO_VIEW (details->computer_view));
    }
    if (selection == NULL)
    {
        selection = nemo_view_get_selection (NEMO_VIEW (details->network_view));
    }
	return selection;
}


static GList *
nemo_index_view_get_selection_for_file_transfer (NemoView *view)
{
    g_return_val_if_fail (NEMO_IS_INDEX_VIEW (view), NULL);
	return nemo_index_view_get_selection (view);
}

static guint
nemo_index_view_get_item_count (NemoView *view)
{
    g_return_val_if_fail (NEMO_IS_INDEX_VIEW (view), 0);
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;
	return details->number_of_files;
}

static gboolean
nemo_index_view_is_empty (NemoView *view)
{
    g_return_val_if_fail (NEMO_IS_INDEX_VIEW (view), FALSE);
	return FALSE;
}

static void
nemo_index_view_end_file_changes (NemoView *view, gpointer user_data)
{
    /* g_return_if_fail (NEMO_IS_INDEX_VIEW (user_data));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (user_data);
    NemoIndexViewDetails *details = index_view->details;
    */
}

static void
nemo_index_view_remove_file (NemoView *view, NemoFile *file, NemoDirectory *directory, gpointer user_data)
{
    g_return_if_fail (NEMO_IS_INDEX_VIEW (user_data));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (user_data);
    NemoIndexViewDetails *details = index_view->details;
    if (nemo_index_view_check_file_validity (file, directory))
    {
        details->number_of_files--;

        NemoViewClass *view_class = NULL;
        guint files_count = 0;

        if (view == details->xdg_view)
        {
            view_class = NEMO_VIEW_GET_CLASS (details->xdg_view);
            files_count = -1 + view_class->get_item_count (details->xdg_view);
            nemo_index_view_update_expander_count_label (details->xdg_count, files_count);
        }
        if (view == details->computer_view)
        {
            view_class = NEMO_VIEW_GET_CLASS (details->computer_view);
            files_count = -1 + view_class->get_item_count (details->computer_view);
            nemo_index_view_update_expander_count_label (details->computer_count, files_count);
        }
        if (view == details->network_view)
        {
            view_class = NEMO_VIEW_GET_CLASS (details->network_view);
            files_count = -1 + view_class->get_item_count (details->network_view);
            nemo_index_view_update_expander_count_label (details->network_count, files_count);
        }
        if (details->view_mode == INDEX_VIEW_LIST)
        {
            GtkTreeView *tree_view = nemo_list_view_get_tree_view (NEMO_LIST_VIEW (view));
            gtk_tree_view_columns_autosize (tree_view);
        }
    }
}

static void
nemo_index_view_set_selection (NemoView *view, GList *selection)
{
	nemo_view_notify_selection_changed (view);
}

static void
nemo_index_view_select_all (NemoView *view)
{

}

static void
nemo_index_view_reveal_selection (NemoView *view)
{

}

static void
nemo_index_view_merge_menus (NemoView *view)
{
    g_return_if_fail (NEMO_IS_INDEX_VIEW (view));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;

    NEMO_VIEW_CLASS (nemo_index_view_parent_class)->merge_menus (view);
    NemoViewClass *view_class = NULL;

    view_class = NEMO_VIEW_GET_CLASS (details->xdg_view);
    view_class->merge_menus (details->xdg_view);

    view_class = NEMO_VIEW_GET_CLASS (details->computer_view);
    view_class->merge_menus (details->computer_view);

    view_class = NEMO_VIEW_GET_CLASS (details->network_view);
    view_class->merge_menus (details->network_view);
}

static void
nemo_index_view_unmerge_menus (NemoView *view)
{
    g_return_if_fail (NEMO_IS_INDEX_VIEW (view));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;
    NemoViewClass *view_class = NULL;
    if (details->xdg_view)
    {
        view_class = NEMO_VIEW_GET_CLASS (details->xdg_view);
        view_class->unmerge_menus (details->xdg_view);
    }
    if (details->computer_view)
    {
        view_class = NEMO_VIEW_GET_CLASS (details->computer_view);
        view_class->unmerge_menus (details->computer_view);
    }
    if (details->network_view)
    {
        view_class = NEMO_VIEW_GET_CLASS (details->network_view);
        view_class->unmerge_menus (details->network_view);
    }
	NEMO_VIEW_CLASS (nemo_index_view_parent_class)->unmerge_menus (view);
}

static void
nemo_index_view_update_menus (NemoView *view)
{
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    //NemoIndexViewDetails *details = index_view->details;
	NEMO_VIEW_CLASS (nemo_index_view_parent_class)->update_menus (view);
    nemo_index_do_update_menus (index_view, NULL);
}

/* Reset sort criteria and zoom level to match defaults */
static void
nemo_index_view_update_to_defaults (NemoView *view)
{
    g_return_if_fail (NEMO_IS_INDEX_VIEW (view));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;
    NemoViewClass *view_class = NULL;

    view_class = NEMO_VIEW_GET_CLASS (details->xdg_view);
    view_class->reset_to_defaults (details->xdg_view);

    view_class = NEMO_VIEW_GET_CLASS (details->computer_view);
    view_class->reset_to_defaults (details->computer_view);

    view_class = NEMO_VIEW_GET_CLASS (details->network_view);
    view_class->reset_to_defaults (details->network_view);

}

static void
nemo_index_view_bump_zoom_level (NemoView *view, int zoom_increment)
{
    g_return_if_fail (NEMO_IS_INDEX_VIEW (view));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;

    NemoZoomLevel new_level = details->zoom_level + zoom_increment;
    nemo_index_view_set_zoom_level (index_view, new_level);
}

static NemoZoomLevel
nemo_index_view_get_zoom_level (NemoView *view)
{
    g_return_val_if_fail (NEMO_IS_INDEX_VIEW (view), NEMO_ZOOM_LEVEL_STANDARD);
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;
    return details->zoom_level;
}

static void
nemo_index_view_zoom_to_level (NemoView *view, NemoZoomLevel zoom_level)
{
    g_return_if_fail (NEMO_IS_INDEX_VIEW (view));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    nemo_index_view_set_zoom_level (index_view, zoom_level);
}

static void
nemo_index_view_restore_default_zoom_level (NemoView *view)
{
    g_return_if_fail (NEMO_IS_INDEX_VIEW (view));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;
    NemoZoomLevel default_level = NEMO_ZOOM_LEVEL_STANDARD;
    if (details->view_mode == INDEX_VIEW_LIST)
    {
        default_level = NEMO_ZOOM_LEVEL_SMALLEST;
    }
    nemo_index_view_set_zoom_level (index_view, default_level);
}

static gboolean
nemo_index_view_can_zoom_in (NemoView *view)
{
    g_return_val_if_fail (NEMO_IS_INDEX_VIEW (view), FALSE);
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;
	return details->zoom_level < NEMO_ZOOM_LEVEL_LARGEST;
}

static gboolean
nemo_index_view_can_zoom_out (NemoView *view)
{
	g_return_val_if_fail (NEMO_IS_INDEX_VIEW (view), FALSE);
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;
	return details->zoom_level > NEMO_ZOOM_LEVEL_SMALLEST;
}

static void
nemo_index_view_click_policy_changed (NemoView *directory_view)
{

}

static int
nemo_index_view_compare_files (NemoView *view, NemoFile *file1, NemoFile *file2)
{
    char *display_name1, *display_name2;
    gchar volume_symbol1, volume_symbol2;

    //如果文件名称中含有盘符，按照盘符顺序排列
    display_name1 = nemo_file_get_display_name (file1);
    display_name2 = nemo_file_get_display_name (file2);
    volume_symbol1 = nemo_get_volume_symbol (display_name1);
    volume_symbol2 = nemo_get_volume_symbol (display_name2);
    g_free (display_name1);
    g_free (display_name2);

    if (volume_symbol1 && volume_symbol2) {
        //盘符小的排在前面
        if (volume_symbol1 < volume_symbol2) {
            return -1;
        }

        //盘符大的排在后面
        if (volume_symbol1 > volume_symbol2) {
            return +1;
        }
    }

    if (file1 < file2) {
		return -1;
	}

	if (file1 > file2) {
		return +1;
	}

	return 0;
}

static gboolean
nemo_index_view_using_manual_layout (NemoView *view)
{
	return FALSE;
}

static void
nemo_index_view_end_loading (NemoView *view, gboolean all_files_seen, gpointer user_data)
{
    g_return_if_fail (NEMO_IS_INDEX_VIEW (user_data));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (user_data);
    NemoIndexViewDetails *details = index_view->details;
    if (!nemo_view_get_loading (details->xdg_view) &&
        !nemo_view_get_loading (details->computer_view) &&
        !nemo_view_get_loading (details->network_view))
    {
        details->done_loading = TRUE;
        nemo_view_display_selection_info (NEMO_VIEW (index_view));
        //子视图与独立视图存在关联性，需要将其统一重置。
        NemoZoomLevel zoom_level = nemo_view_get_zoom_level (details->computer_view);
        nemo_view_zoom_to_level (NEMO_VIEW (index_view), zoom_level);
    }
}

static char *
nemo_index_view_get_first_visible_file (NemoView *view)
{
	return NULL;
}

static void
nemo_index_view_scroll_to_file (NemoView *view,
			      const char *uri)
{

}

static void
nemo_index_view_sort_directories_first_changed (NemoView *view)
{
}

static const gchar *
nemo_index_view_get_id (NemoView *view)
{
    g_return_val_if_fail (NEMO_IS_INDEX_VIEW (view), NULL);
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoIndexViewDetails *details = index_view->details;
	return details->current_id;
}

static gboolean
nemo_index_view_is_read_only (NemoView *view)
{
    return TRUE;
}

static void
nemo_index_view_start_renaming_file (NemoView *view,
				  NemoFile *file,
				  gboolean select_all)
{
    g_return_if_fail (NEMO_IS_INDEX_VIEW (view));
    NemoIndexView *index_view = NEMO_INDEX_VIEW (view);
    NemoView *subview = nemo_index_view_get_selection_view (index_view);
    NemoViewClass *view_class = NULL;

    view_class = NEMO_VIEW_GET_CLASS (subview);
    view_class->start_renaming_file (subview, file, select_all);
}

static void
nemo_index_view_set_current_id (NemoIndexView *index_view, const gchar *id)
{
    NemoIndexViewDetails *details = index_view->details;
    details->current_id = g_strdup (id);

    if (g_strcmp0 (id, NEMO_INDEX_VIEW_ICON_ID) == 0)
    {
        details->view_mode = INDEX_VIEW_ICON;
    }
    else if (g_strcmp0 (id, NEMO_INDEX_VIEW_COMPACT_ID) == 0)
    {
        details->view_mode = INDEX_VIEW_COMPACT;
    }
    else if (g_strcmp0 (id, NEMO_INDEX_VIEW_LIST_ID) == 0)
    {
        details->view_mode = INDEX_VIEW_LIST;
    } else {
        details->view_mode = INDEX_VIEW_NONE;
    }
}

static void
nemo_index_view_constructed (NemoIndexView *index_view, NemoWindowSlot *slot)
{
    NemoIndexViewDetails *details = index_view->details;
    details->slot = slot;
    if (details->view_mode == INDEX_VIEW_LIST)
    {
        nemo_index_view_create_list_header (index_view);
    }
    nemo_index_view_create_computer_view (index_view);
    nemo_index_view_create_xdg_view (index_view);
    nemo_index_view_create_network_view (index_view);
}

static void
nemo_index_subview_dispose (NemoIndexView *index_view, NemoView *subview)
{
    g_signal_handlers_disconnect_by_data (subview, index_view);
    g_object_unref (subview);
}

static void
nemo_index_view_dispose (GObject *object)
{
	NemoIndexView *index_view;
	index_view = NEMO_INDEX_VIEW (object);
    NemoIndexViewDetails *details = index_view->details;
    if (details->bindings)
    {
        g_list_free_full (details->bindings, g_object_unref);
        details->bindings = NULL;
    }

    GtkTreeView *tree_view;
    GtkTreeModel *tree_model;
    if (details->list_header)
    {
        tree_view = nemo_list_view_get_tree_view (NEMO_LIST_VIEW (details->list_header));
        tree_model = gtk_tree_view_get_model (tree_view);
        //disconnet for list header
        g_signal_handlers_disconnect_by_data (tree_view, index_view);
        g_signal_handlers_disconnect_by_data (tree_model, index_view);
        g_object_unref (details->list_header);
        details->list_header = NULL;
    }
    if (details->xdg_view)
    {
        nemo_index_subview_dispose (index_view, details->xdg_view);
        details->xdg_view = NULL;
    }
    if (details->computer_view)
    {
        nemo_index_subview_dispose (index_view, details->computer_view);
        details->computer_view = NULL;
    }
    if (details->network_view)
    {
        nemo_index_subview_dispose (index_view, details->network_view);
        details->network_view = NULL;
    }
    G_OBJECT_CLASS (nemo_index_view_parent_class)->dispose (object);
}

static void
nemo_index_view_finalize (GObject *object)
{
    NemoIndexView *index_view;
    index_view = NEMO_INDEX_VIEW (object);

    g_free (index_view->details->current_id);

    G_OBJECT_CLASS (nemo_index_view_parent_class)->finalize (object);
}

static void
nemo_index_view_get_property (GObject   *object,
                              guint     prop_id,
                              GValue    *value,
                              GParamSpec    *pspec)
{
    NemoIndexView *index_view = NEMO_INDEX_VIEW (object);
    NemoIndexViewDetails *details = index_view->details;

    switch (prop_id)
    {
        case PROP_CURRENT_ID:
            g_value_set_string (value, details->current_id);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
    }
}

static void
nemo_index_view_set_property (GObject   *object,
                              guint     prop_id,
                              const GValue  *value,
                              GParamSpec    *pspec)
{
    NemoIndexView *index_view = NEMO_INDEX_VIEW (object);
    const gchar *view_id = NULL;
    switch (prop_id)
    {
        case PROP_CURRENT_ID:
            view_id = (const gchar *)g_strdup (g_value_get_string (value));
            nemo_index_view_set_current_id (index_view, view_id);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
    }
}

static void
nemo_index_view_class_init (NemoIndexViewClass *class)
{
	NemoViewClass *nemo_view_class;
    g_type_class_add_private (class, sizeof (NemoIndexViewDetails));
	nemo_view_class = NEMO_VIEW_CLASS (class);

    G_OBJECT_CLASS (class)->set_property = nemo_index_view_set_property;
    G_OBJECT_CLASS (class)->get_property = nemo_index_view_get_property;
	G_OBJECT_CLASS (class)->dispose = nemo_index_view_dispose;
	G_OBJECT_CLASS (class)->finalize = nemo_index_view_finalize;
    //G_OBJECT_CLASS (class)->constructed = nemo_index_view_constructed;

    //nemo_view_class->add_file = nemo_index_view_add_file;
	nemo_view_class->begin_loading = nemo_index_view_begin_loading; //
	nemo_view_class->bump_zoom_level = nemo_index_view_bump_zoom_level;
	nemo_view_class->can_zoom_in = nemo_index_view_can_zoom_in;
	nemo_view_class->can_zoom_out = nemo_index_view_can_zoom_out;
    nemo_view_class->click_policy_changed = nemo_index_view_click_policy_changed; //
	nemo_view_class->clear = nemo_index_view_clear;
	nemo_view_class->file_changed = nemo_index_view_file_changed; //
	nemo_view_class->get_selection = nemo_index_view_get_selection;
	nemo_view_class->get_selection_for_file_transfer = nemo_index_view_get_selection_for_file_transfer;
	nemo_view_class->get_item_count = nemo_index_view_get_item_count;
	nemo_view_class->is_empty = nemo_index_view_is_empty;
	//nemo_view_class->remove_file = nemo_index_view_remove_file;
	nemo_view_class->merge_menus = nemo_index_view_merge_menus;
    nemo_view_class->unmerge_menus = nemo_index_view_unmerge_menus;
	nemo_view_class->update_menus = nemo_index_view_update_menus;
	nemo_view_class->reset_to_defaults = nemo_index_view_update_to_defaults;
	nemo_view_class->restore_default_zoom_level = nemo_index_view_restore_default_zoom_level;
	nemo_view_class->reveal_selection = nemo_index_view_reveal_selection;
	nemo_view_class->select_all = nemo_index_view_select_all;
	nemo_view_class->set_selection = nemo_index_view_set_selection;
	nemo_view_class->compare_files = nemo_index_view_compare_files;
	nemo_view_class->sort_directories_first_changed = nemo_index_view_sort_directories_first_changed;
	nemo_view_class->get_zoom_level = nemo_index_view_get_zoom_level;
	nemo_view_class->zoom_to_level = nemo_index_view_zoom_to_level;
	//nemo_view_class->end_file_changes = nemo_index_view_end_file_changes;
	nemo_view_class->using_manual_layout = nemo_index_view_using_manual_layout;
	//nemo_view_class->end_loading = nemo_index_view_end_loading;
	nemo_view_class->get_view_id = nemo_index_view_get_id;
	nemo_view_class->get_first_visible_file = nemo_index_view_get_first_visible_file;
	nemo_view_class->scroll_to_file = nemo_index_view_scroll_to_file;
    nemo_view_class->is_read_only = nemo_index_view_is_read_only;
    nemo_view_class->start_renaming_file = nemo_index_view_start_renaming_file;

    g_object_class_install_property (G_OBJECT_CLASS (class),
                                     PROP_CURRENT_ID,
                                     g_param_spec_string ("current-id",
                                                          "Current Id",
                                                          "The id of current view used",
                                                          NULL,
                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)
                                     );
}

static void
nemo_index_view_expander_reset_header (GtkWidget *expander, GtkWidget *count_label)
{
    GtkWidget *header_box;
    GtkWidget *name_label;
    const gchar *name;

    name = gtk_expander_get_label (GTK_EXPANDER (expander));

    header_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
    GtkStyleContext *style = gtk_widget_get_style_context (header_box);
    gtk_style_context_add_class (style, "nemo-expander-header");

    name_label = gtk_label_new (name);

    gtk_box_pack_start (GTK_BOX (header_box), name_label, FALSE, FALSE, 5);
    gtk_box_pack_start (GTK_BOX (header_box), count_label, FALSE, FALSE, 5);

    gtk_expander_set_label_widget (GTK_EXPANDER (expander), header_box);
}

static void
nemo_index_view_expander_setup (NemoIndexView *index_view, GtkWidget *expander)
{
    NemoIndexViewDetails *details = index_view->details;
    gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);
    gtk_expander_set_label_fill (GTK_EXPANDER (expander), TRUE);
    gtk_expander_set_resize_toplevel (GTK_EXPANDER (expander), FALSE);
    gtk_widget_set_valign (expander, GTK_ALIGN_START);

    gtk_box_pack_start (GTK_BOX (details->index_box), expander, FALSE, FALSE, 5);
    GtkStyleContext *style = gtk_widget_get_style_context (expander);
    gtk_style_context_add_class (style, "nemo-index-expander");
}

static gboolean
button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
    NemoIndexView *index_view = NEMO_INDEX_VIEW (user_data);
    //NemoIndexViewDetails *details = index_view->details;
    NemoView *selection_view = NULL;
    selection_view = nemo_index_view_get_selection_view (index_view);

    //点击子视图外的空白处，退出选择
    nemo_index_view_unselect_subview (index_view, selection_view);
    gtk_widget_grab_focus (widget);
    if (event->button == 3)
    {
        nemo_index_view_do_popup_menu (index_view, event, NULL);
        return TRUE;
    }
    return FALSE;
}

static void
nemo_index_view_init (NemoIndexView *index_view)
{
	index_view->details = G_TYPE_INSTANCE_GET_PRIVATE (index_view,
                                                       NEMO_TYPE_INDEX_VIEW,
                                                       NemoIndexViewDetails);
    NemoIndexViewDetails *details = index_view->details;

    details->done_loading = FALSE;
    details->zoom_level = NEMO_ZOOM_LEVEL_STANDARD;
    gchar *home = nemo_get_home_directory_uri ();
    details->xdg_location = g_file_new_for_uri (home);
    details->network_location = g_file_new_for_uri ("network:///");
    details->computer_location = g_file_new_for_uri ("computer:///");

    GtkWidget *event_box = gtk_event_box_new ();
    details->event_box = event_box;
    gtk_widget_set_can_focus (event_box, TRUE);
    gtk_container_add (GTK_CONTAINER (index_view), event_box);
    g_signal_connect (event_box,
                    "button-press-event",
                    G_CALLBACK (button_press_callback),
                    index_view);

    details->index_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
    gtk_container_add (GTK_CONTAINER (event_box), details->index_box);

    GtkStyleContext *style = gtk_widget_get_style_context (details->index_box);
    gtk_style_context_add_class (style, "nemo-index");
    g_signal_connect_swapped (GTK_WIDGET (index_view),
                "size-allocate",
                G_CALLBACK (index_box_on_size_allocate),
                index_view);

    //create a box for list views header;
    details->header_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
    gtk_box_pack_start (GTK_BOX (details->index_box), details->header_box, FALSE, TRUE, 0);

    details->xdg_box = gtk_expander_new (_("Home"));
    nemo_index_view_expander_setup (index_view, details->xdg_box);

    details->computer_box = gtk_expander_new (_("Computer"));
    nemo_index_view_expander_setup (index_view, details->computer_box);

    details->network_box = gtk_expander_new (_("Network"));
    nemo_index_view_expander_setup (index_view, details->network_box);

    details->xdg_count = gtk_label_new ("(0)");
    details->computer_count = gtk_label_new ("(0)");
    details->network_count = gtk_label_new ("(0)");

    nemo_index_view_expander_reset_header (details->xdg_box, details->xdg_count);
    nemo_index_view_expander_reset_header (details->computer_box, details->computer_count);
    nemo_index_view_expander_reset_header (details->network_box, details->network_count);

    gtk_widget_show_all (GTK_WIDGET (index_view));
    g_free (home);
}

static NemoView *
nemo_index_view_create_icon (NemoWindowSlot *slot)
{
	NemoIndexView *view;

	view = g_object_new (NEMO_TYPE_INDEX_VIEW,
			     "window-slot", slot,
                 "current-id", NEMO_INDEX_VIEW_ICON_ID,
			     NULL);
    nemo_index_view_constructed (view, slot);
	return NEMO_VIEW (view);
}

static NemoView *
nemo_index_view_create_compact (NemoWindowSlot *slot)
{
	NemoIndexView *view;

	view = g_object_new (NEMO_TYPE_INDEX_VIEW,
			     "window-slot", slot,
                 "current-id", NEMO_INDEX_VIEW_COMPACT_ID,
			     NULL);
    nemo_index_view_constructed (view, slot);
	return NEMO_VIEW (view);
}

static NemoView *
nemo_index_view_create_list (NemoWindowSlot *slot)
{
	NemoIndexView *view;

	view = g_object_new (NEMO_TYPE_INDEX_VIEW,
			     "window-slot", slot,
                 "current-id", NEMO_INDEX_VIEW_LIST_ID,
			     NULL);
    nemo_index_view_constructed (view, slot);
	return NEMO_VIEW (view);
}

static gboolean
nemo_index_view_supports_uri (const char *uri,
				 GFileType file_type,
				 const char *mime_type)
{
	if (g_str_has_prefix (uri, "computer:///")) {
		return TRUE;
	}
	return FALSE;
}

#define TRANSLATE_INDEX_VIEW_INFO(view_info)					\
	view_info.view_combo_label = _(view_info.view_combo_label);	\
	view_info.view_menu_label_with_mnemonic = _(view_info.view_menu_label_with_mnemonic); \
	view_info.error_label = _(view_info.error_label);		\
	view_info.startup_error_label = _(view_info.startup_error_label); \
	view_info.display_location_label = _(view_info.display_location_label); \

static NemoViewInfo nemo_index_view_icon = {
	NEMO_INDEX_VIEW_ICON_ID,
	/* translators: this is used in the view selection dropdown
	 * of navigation windows and in the preferences dialog */
	N_("Computer View"),
	/* translators: this is used in the view menu */
	NULL,
	N_("The computer view encountered an error."),
	N_("The computer view encountered an error while starting up."),
	N_("Display this location with the computer view."),
	nemo_index_view_create_icon,
	nemo_index_view_supports_uri
};

static NemoViewInfo nemo_index_view_compact = {
	NEMO_INDEX_VIEW_COMPACT_ID,
	/* translators: this is used in the view selection dropdown
	 * of navigation windows and in the preferences dialog */
	N_("Computer View"),
	/* translators: this is used in the view menu */
	NULL,
	N_("The computer view encountered an error."),
	N_("The computer view encountered an error while starting up."),
	N_("Display this location with the computer view."),
	nemo_index_view_create_compact,
	nemo_index_view_supports_uri
};

static NemoViewInfo nemo_index_view_list = {
	NEMO_INDEX_VIEW_LIST_ID,
	/* translators: this is used in the view selection dropdown
	 * of navigation windows and in the preferences dialog */
	N_("Computer View"),
	/* translators: this is used in the view menu */
	NULL,
	N_("The computer view encountered an error."),
	N_("The computer view encountered an error while starting up."),
	N_("Display this location with the computer view."),
	nemo_index_view_create_list,
	nemo_index_view_supports_uri
};

void
nemo_index_view_register (void)
{
    TRANSLATE_INDEX_VIEW_INFO (nemo_index_view_icon);
	nemo_view_factory_register (&nemo_index_view_icon);

    TRANSLATE_INDEX_VIEW_INFO (nemo_index_view_list);
	nemo_view_factory_register (&nemo_index_view_list);

    TRANSLATE_INDEX_VIEW_INFO (nemo_index_view_compact);
	nemo_view_factory_register (&nemo_index_view_compact);
}

const gchar *
nemo_index_view_get_id_by_subview_id (const gchar *id)
{
    const gchar *view_id = NULL;
    if (g_strcmp0 (id, NEMO_ICON_VIEW_ID) == 0 ||
        g_strcmp0 (id, NEMO_INDEX_VIEW_ICON_ID) == 0)
    {
        view_id = NEMO_INDEX_VIEW_ICON_ID;
    }
    else if (g_strcmp0 (id, FM_COMPACT_VIEW_ID) == 0 ||
             g_strcmp0 (id, NEMO_INDEX_VIEW_COMPACT_ID) == 0)
    {
        view_id = NEMO_INDEX_VIEW_COMPACT_ID;
    }
    else if (g_strcmp0 (id, NEMO_LIST_VIEW_ID) == 0 ||
             g_strcmp0 (id, NEMO_INDEX_VIEW_LIST_ID) == 0)
    {
        view_id = NEMO_INDEX_VIEW_LIST_ID;
    }
    return view_id;
}

const gchar *
nemo_index_view_get_subview_id (const gchar *id)
{
    const gchar *view_id = NULL;
    if (g_strcmp0 (id, NEMO_INDEX_VIEW_ICON_ID) == 0 ||
        g_strcmp0 (id, NEMO_ICON_VIEW_ID) == 0)
    {
        view_id = NEMO_ICON_VIEW_ID;
    }
    else if (g_strcmp0 (id, NEMO_INDEX_VIEW_COMPACT_ID) == 0 ||
             g_strcmp0 (id, FM_COMPACT_VIEW_ID) == 0)
    {
        view_id = FM_COMPACT_VIEW_ID;
    }
    else if (g_strcmp0 (id, NEMO_INDEX_VIEW_LIST_ID) == 0 ||
             g_strcmp0 (id, NEMO_LIST_VIEW_ID) == 0)
    {
        view_id = NEMO_LIST_VIEW_ID;
    }
    return view_id;
}
